;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;; WORK LOGGER ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#NoEnv
; ##############################################################################
; Auto-Execute Section
; ##############################################################################
AutoTrim, Off
SetBatchLines, -1
SetWinDelay, 0
OnExit, Exit_App
; Variables Defaults
Undo_Mode := False
Undo_Text := ""
View_Mode := False
Gui96_Title := ""
CCAD_ID := 0
Tray_ID := 0
Save_BT := True
Last_Sales := ""
Last_Year := ""
Last_Month := ""
; Variables for Windows/Areas
_ID := 0
_I := 0
_X := 0
_Y := 0
_W := 0
_H := 0
_L := 0
_R := 0
_T := 0
_B := 0
; Set Workable Area Mode: Set / Res(store)
WA_Mode := "Set"
; Plan on adding this to .ini
Logger_Font := "Courier New"
; Variables for Files and Log
CCAD_Path := "" ; must include trailing \
CCAD_App := "" ; name of the exe file
Log_Dir := A_ScriptDir . "\" . A_Username . "-logs"
INI_Path := Log_Dir . "\WorkLogger.ini"
INI_Section := "WorkLogger"
INI_Filekey := "LastSales"
INI_Fontkey := "Font"
Sales_File := "Sales.txt"
FormatTime, File_Date, , dd_ddd
FormatTime, File_Month, , MM_MMM
FormatTime, File_Year, , yyyy
FormatTime, File_Time, , ddd MMM dd yyyy
FormatTime, Log_Time, , h:mm:ss
; Create Folders and Logpath
FileCreateDir, %Log_Dir%
File_Dir := Log_Dir . "\" . File_Year . "\" . File_Month
If (!InStr(FileExist(File_Dir), "D")) {  ; folder doesn't exist
   FileCreateDir, %File_Dir%
   If (Errorlevel) {
      MsgBox % "Couldn't create folder " . File_Dir . "!`n"
             . "Please contact your system administrator!`n"
             . "The program will exit!"
      ExitApp
   }
}
File_Path := File_Dir . "\" . File_Date . ".txt"
; Read INI
Gosub, Read_INI
; Check for new sales
Gosub, Check_Sales
; Create Main Gui
Gosub, Gui95_Create
; Check for Contact Center Agent Desktop
CCAD_H := 0
Gosub, Check_CCAD
WA_Top += CCAD_H
; Set workable Area to exclude Main Gui, so never can be covered over or under
; Thanks to Shimanov and Laszlo
WA_Mode := "Set"
Gosub, Set_Working_Area
; Show Gui
Gosub, Gui95_Show
Return
; ##############################################################################
; Gui 95 - Main Gui
; ##############################################################################
; ------------------------------------------------------------------------------
Gui95_Create:
; ------------------------------------------------------------------------------
; Build dynamic Gui, commented out controls are future plans
; Get current main Monitor's Display (MD_) and Working (MW_) Areas
SysGet, MD_, Monitor
MD_Width := MD_Right - MD_Left
MD_Height := MD_Bottom - MD_Top
SysGet, MW_, MonitorWorkArea
MW_Width := MW_Right - MW_Left
MW_Height := MW_Bottom - MW_Top
; New Workable Area
WA_Left := MW_Left
WA_Right := MW_Right
WA_Top := MW_Top
WA_Bottom := MW_Bottom
WA_Width := MW_Width
WA_Height := MW_Height
; Set Gui's Dimensions
Gui95_X := WA_Left
Gui95_Y := WA_Bottom - 3
Gui95_W := WA_Width
; Get Taskbar's Size, Position and State
WinGet, Tray_ID, ID, ahk_class Shell_TrayWnd
WinGetPos TrayX, TrayY, TrayW, TrayH, ahk_class Shell_TrayWnd
Tray_Vis := True
If (TrayW > TrayH) {
   ; Horizontal Tray
   If (TrayY > (MD_Bottom - (TrayH // 2))) {
      ; Bottom - not visible
      Tray_Vis := False
   } Else {
      ; Top - Visibilaty not important
      Tray_Vis := True
   }
}
If (TrayH > TrayW) {
   ; Vertical Tray
   If (TrayX < (MD_Left - (TrayW // 2))) {
      ; Left - not visible
      Tray_Vis := False
   }
   If (TrayX > (MD_Right - (TrayW // 2))) {
      ; Right - not visible
      Tray_Vis := False
   }
}
; Gui's Margins
Gui95_XM := 10
Gui95_YM := 10
; Button's Width, Height, Colums, Rows and Margins
BT95_W := 50
BT95_H := 20
BT95_C := 2
BT95_R := 2
BT95_M := 10
; Edit's Width and Height
ED95_W := Gui95_W - (BT95_W * BT95_C) - (Gui95_XM * (BT95_C + 2))
ED95_H := (BT95_R * BT95_H) + (BT95_M * (BT95_R - 1))
; Gui Options
Gui, 95:+AlwaysOnTop -Caption +ToolWindow +Border +LabelGui95_
; Gui Margins: Left/Right = 10, Top/Bottom = 5
Gui, 95:Margin, %Gui95_XM%, %Gui95_YM%
; Font for Edit Box
Gui, 95:Font, s10 cBlack, %Logger_Font%
; Edit Box
Gui, 95:Add, Edit, w%ED95_W% h%ED95_H% vGui95_EDLog
; Font for buttons
Gui, 95:Font, s8, Verdana
; (Still working on) logs in "self sorting rotating txt file"
;( hereafter referred to as SSRTF)
Gui, 95:Add, Button, Default ym w%BT95_W% h%BT95_H% gGui95_BTSend,&Send
; Brings last Var back into Editbox paste differntly (with [EDIT] Tage)
; on Next Send
Gui, 95:Add, Button, xp y+%BT95_M% wp hp gGui95_BTUndo, &Undo
; Spawns new edit box with entire contents of SSRTF
Gui, 95:Add, Button, ym wp hp gGui95_BTLog, Lo&g
; (Still working on) Spawns input box (which Searches entire contents of all
; SSRTF's, (including sub directories) for string from inputbox,
; and post datestamp and contents  of Var)
Gui, 95:Add, Button, xp y+%BT95_M% wp hp gGui95_BTFind, &Find
/*
; (Still working on) Creates MMMTimeSheet.txt then Spawns a drop down box with
; Break1,Break2,Break3,& Lunch. On Select it post current time Such As
; `[%File_Date%`](Only once per day) Break 1 = %CurrentDateTime% then returns
; MsgBox that says Return by (%currenttime% + Respective amount of minutes
; for break type)
Gui, 95:add, button,disabled ym, T&mSh
; (Still working on) Same as above except input box for Customers account number
; and Work order number. and no time involved
Gui, 95:add, button,disabled, `$a&Le
; (Still working on) prompts user to select a number of minutes.
; Creates taskbar entry that displays count down and Flashes continuosly until
; user clicks taskbar entry at which time it disapears.
Gui, 95:add, button,disabled ym, &Timer
; (Still working on) Spawns Input box for customers information and prompts to
; Chose date and time which sets alarm for follow up
Gui, 95:add, button,disabled, &Alarm
; (Still working on) Brings up a file (encrypted maybe) which stores all
; internal work passwords
Gui, 95:add, button, disabled ym,&PsWrd
; (Still working on) Brings up a menu list with options to launch or add daily
; programs that are routinely used. (chose using file select I assume)
Gui, 95:add, button,disabled,Lnchr
*/
Gui, 95:Show, Hide
Gui, 95:+Lastfound
Gui95_ID := WinExist()
WinGetPos, , , , Gui95_H
Gui95_Y -= Gui95_H
WA_Bottom := Gui95_Y - 1
Return
; ------------------------------------------------------------------------------
Gui95_Show:
; ------------------------------------------------------------------------------
Gui, 95:Default
; Set Focus on Edit
GuiControl, Focus, Gui95_EDLog
; Show the Gui
Gui, 95:Show, x%Gui95_X% y%Gui95_Y% w%Gui95_W% h%Gui95_H%, WorkLogger
; Send the Cursor to the End of Text
Send ^{End}
; If taskbar is hidden, watch it
If (!Tray_Vis) {
   SetTimer, Watch_Tray, 200
}
Return
; ------------------------------------------------------------------------------
Gui95_Close:
Gui95_Escape:
; ------------------------------------------------------------------------------
; Bye, bye!
Gui, 95:Destroy
ExitApp
; ------------------------------------------------------------------------------
Gui95_BTSend:
; ------------------------------------------------------------------------------
Gui, 95:Submit, NoHide
; If Gui95_EDLog is empty, do nothing
If (Gui95_EDLog <> "") {
   ; Save Entry for Undo
   Undo_Text = %Gui95_EDLog%
   ; First convert CRLF to LF
   Gui95_EDLog := RegExReplace(Gui95_EDLog, "\r\n", "\n")
   ; Then replace CR and LF with SPace
   Gui95_EDLog := RegExReplace(Gui95_EDLog, "(\r|\n)+", " ")
   If (Undo_Mode) {
      ; Undo append [Edit]
      FileAppend, [Edit] %Gui95_EDLog%`n, %File_Path%
      Undo_Mode := False
   } Else {
      ; Normal append [Time]
      FormatTime, Log_Time,, h:mm:ss
      FileAppend,`n[%Log_Time%] %Gui95_EDLog%`n, %File_Path%
   }
   ; Clear Variable and Edit
   Gui95_EDLog =
   GuiControl, , Gui95_EDLog,
}
; Set Focus on Edit
GuiControl, 95:Focus, Gui95_EDLog
; Send the Cursor to the End of Text
Send ^{End}
Return
; ------------------------------------------------------------------------------
Gui95_BTUndo:
; ------------------------------------------------------------------------------
; Append with [EDIT]
Gui, 95:Default
If (Undo_Text <> "") {
   ; Toggle Undo Mode
   Undo_Mode := (!Undo_Mode)
   If (Undo_Mode) {
      GuiControl, , Gui95_EDLog, %Undo_Text%
   } Else {
      GuiControl, , Gui95_EDLog,
   }
}
GuiControl, Focus, Gui95_EDLog
; Send the Cursor to the End of Text
Send, ^{End}
Return
; ------------------------------------------------------------------------------
Gui95_BTFind:
; ------------------------------------------------------------------------------
; Searches entire Contents of all SSRTF's (including Sub Directories)
; for String in Logentry and post matching Lines in a new read only Edit Box
Gui, 95:Submit, NoHide
If (Gui95_EDLog = "") {
   MsgBox, % "Input Search String, please!"
   Return
}
Gui, 95:+Disabled
ToolTip, Searching for %Gui95_EDLog%
Loop,%Log_Dir%\*.txt, 0, 1
{
   ; Don'tsearch in sales files
   If (A_LoopFileName = Sales_File) {
      Continue
   }
   ; Strip Log_Dir from File Path (e.g. 2007/01.Jan/0129-Mon.txt)
   Found_In_File := "["
                  . SubStr(A_LoopFileFullPath, StrLen(Log_Dir) + 2)
                  . "]`r`n"
   Loop Read, %A_LoopFileFullPath%
   {
      If (InStr(A_LoopReadLine, Gui95_EDLog)) {
         Search_Result .= Found_In_File . A_LoopReadLine . "`r`n"
         ; Write the Filename only once
         Found_In_File := ""
      }
   }
   If (Found_In_File = "") {  ; String was found
      Search_Result .= "`r`n"
   }
}
ToolTip
Gui, 95:-Disabled
; Nothing found?
If (Search_Result = "") {
   MsgBox, % "Sorry, """ . Gui95_EDLog . """ wasn't found!"
   Return
}
Gui96_Title := "Matches for """ . Gui95_EDLog . """:"
Log_Read := Search_Result
Search_Result := ""
View_Mode := True
GuiControl, 95:, Gui95_EDLog,
Gosub, Gui96_Show
GuiControl, 95:Focus, Gui95_EDLog
; Send the Cursor to the End of Text
Send, ^{End}
Return
; ------------------------------------------------------------------------------
Gui95_BTLog:
; ------------------------------------------------------------------------------
; Reads today's SSRTF into Log_Read Variable to show it in Gui 96
Log_Path := File_Path
If (!FileExist(Log_Path)) {
   Log_Read := "`nToday's Logfile " . Log_Path . " doesn't exist!"
   Save_BT := False
} Else {
   FileRead, Log_Read, %Log_Path%
}
View_Mode := False
Gosub, Gui96_Show
GuiControl, 95:Focus, Gui95_EDLog
; Send the Cursor to the End of Text
Send, ^{End}
Return
; ##############################################################################
; Gui 96 - Viewer Gui
; ##############################################################################
; ------------------------------------------------------------------------------
Gui96_Show:
; ------------------------------------------------------------------------------
; Creates Edit box with all of today's notes
; Save replaces with edit boxes contents, Cancel does nothing
Gui, 96:Default
ED96_W := WA_Right - 300
ED96_H := WA_Bottom - 300
BT96_W := 80
BT96_X := 0
Gui, 96:+Owner95 +Alwaysontop +Toolwindow +LabelGui96_
Gui, 96:Margin, 10, 10
Gui, 96:Font, s8, %Logger_Font%
Gui, 96:Add, Edit, w%ED96_W% h%ED96_H% vGui96_EDLog , %Log_Read%
GuiControlGet, Pos_, 96:pos, Gui96_EDLog
Gui, 96:Font, Norm s8 CBlack, Verdana
If (View_Mode) {
   GuiControl, 96:+Readonly, Gui96_EDLog
   Gui, 96:Add, Button, Default w%BT96_W% h20 gGui96_Close, &OK
} Else {
   Gui, 96:Add, Button, Default w%BT96_W% h20 vGui96_BTSave gGui96_BTSave, &Save
   If (!Save_BT) {
      GuiControl, 96:+Disabled, Gui96_BTSave
   }
   BT96_X := Pos_X + ((ED96_W - BT96_W) // 2)
   Gui, Add, Button, x%BT96_X% yp wp hp gGui96_BTArchives, &Archives
   BT96_X := Pos_X + ED96_W - BT96_W
   Gui, 96:Add, Button, x%BT96_X% yp wp hp gGui96_Close, &Cancel
}
If (Gui96_Title = "") {
   Gui96_Title := "Logfile:  " . SubStr(Log_Path, StrLen(Log_Dir) + 2)
}
Gui, 96:Show, Center, %Gui96_Title%
If (View_Mode) {
   Send, ^{Home}
} Else {
   Send, ^{End}}
}
Log_Read := ""
Gui96_Title := ""
View_Mode := False
Save_BT := True
Return
; ------------------------------------------------------------------------------
Gui96_BTSave:
; ------------------------------------------------------------------------------
Gui, 96:Submit, NoHide
FileDelete %File_Path%
FileAppend, %Gui96_EDLog%, %File_Path%
Gui, 96:Destroy
Return
; ------------------------------------------------------------------------------
Gui96_BTArchives:
; ------------------------------------------------------------------------------
Gui, 96:+OwnDialogs
FileSelectFile, Log_Path, 3, %Log_Dir%, Select LogFile: , LogFiles (*.txt)
If (Log_Path = "") {
   Return
}
If (!FileExist(Log_Path)) {
   MsgBox, Couldn't find Logfile %Log_Path%
   Return
}
FileRead, Log_Read, %Log_Path%
View_Mode := True
Gui, 96:Destroy
Gosub, Gui96_Show
Return
; ------------------------------------------------------------------------------
Gui96_Close:
Gui96_Escape:
; ------------------------------------------------------------------------------
Gui, 96:Destroy
Return
; ##############################################################################
; Timer
; ##############################################################################
; ------------------------------------------------------------------------------
Watch_Tray:
; ------------------------------------------------------------------------------
; If Taskbar is shown, reset AlwaysOnTop
WinGetPos TrayX, TrayY, TrayW, TrayH, ahk_class Shell_TrayWnd
Tray_Vis := False
If (TrayW > TrayH) {
   ; Horizontal Tray
   If (TrayY > (MD_Height // 2)) {
      ; Bottom
      If (TrayY < (MD_Bottom - (TrayH // 2))) {
         ; visible
         Tray_Vis := True
      }
   }
}
If (TrayH > TrayW) {
   ; Vertical Tray
   If (TrayX < (MD_Widht // 2)) {
      ; Left
      If ((TrayX + (TrayW // 2)) > MD_Left) {
         ; visible
         Tray_Vis := True
      }
   } Else {
      ; Right
      If (TrayX < (MD_Right - (TrayW // 2))) {
      ; visible
      Tray_Vis := True
      }
   }
}
If (Tray_Vis) {
   Gui, 95:-AlwaysOnTop
} Else {
   Gui, 95:+AlwaysOnTop
}
Return
; ##############################################################################
; Hotkeys
; ##############################################################################
; Capslock & r::
; Set_Work_Area(MD_Left, MD_Top, MD_Right, MD_Bottom)
; ExitApp
; ##############################################################################
; Other Subroutines
; ##############################################################################
; ------------------------------------------------------------------------------
Read_INI:
; ------------------------------------------------------------------------------
; Reads the WorkLogger.ini file
; Name of the last processed logfile
IniRead, Last_Sales, %INI_Path%, %INI_Section%, %INI_Filekey%, ERROR
If ((Last_Sales = "ERROR") Or (!FileExist(Last_Sales))) {
   FormatTime, Last_Sales, 20000101000000, yyyy\MM_MMM\dd_ddd
   Last_Sales := Log_Dir . "\" . Last_Sales . ".txt"
}
Return
; ------------------------------------------------------------------------------
Check_Sales:
; ------------------------------------------------------------------------------
; Checks logfiles for sales and stores the found lines in yyyy\MM_MMM\Sales.txt
Loop, %Log_Dir%\*.*, 2, 1
{
   ; Avoid year's folder
   If (StrLen(A_LoopFileFullPath) = StrLen(Log_Dir . "\yyyy")) {
      Continue
   }
   ; Avoid folders older than year/month in Last_Sales file name
   If (A_LoopFileFullPath < SubStr(Last_Sales, 1, StrLen(A_LoopFileFullPath))) {
      Continue
   }
   ; Clear sales var
   Sales_Content := ""
   ; Read Sales_File, if already exists
   If (FileExist(A_LoopFileFullPath . "\" . Sales_File)) {
      FileRead, Sales_Content, %A_LoopFileFullPath%\%Sales_File%
   }
   ; Step through log files
   Loop, %A_LoopFileFullPath%\*.txt
   {
      ; Avoid Sales_Files, the current log file or all files older than or
      ; equal Last_Sales file
      If ((A_LoopFileName = Sales_File)
         Or (A_LoopFileFullPath = File_Path)
         Or (A_LoopFileFullPath <= Last_Sales)) {
         Continue
      }
      Found_In_File := "["
                     . SubStr(A_LoopFileFullPath, StrLen(Log_Dir) + 2)
                     . "] "
      New_Sales := False
      ; Search for sales ($$)
      Loop, Read, %A_LoopFileFullPath%
      {
         If (InStr(A_LoopReadLine, "$$")) {
            Sales_Line := Found_In_File . A_LoopReadLine
            If (!InStr(Sales_Content, Sales_Line)) {
               Sales_Content .= Sales_Line . "`r`n"
               New_Sales := True
            }
         }
      }
      If (New_Sales) {  ; String was found
         Sales_Content .= "`r`n"
      }
      ; Store last logfile's name in INI
      IniWrite, %A_LoopFileFullPath%, %INI_Path%, %INI_Section%, %INI_Filekey%
   }
   ; Rewrite Sales_File, if new entries were found
   If (New_Sales) {
      FileDelete, %A_LoopFileFullPath%\%Sales_File%
      FileAppend, %Sales_Content%, %A_LoopFileFullPath%\%Sales_File%
   }
}
; Free memory
Sales_Content := ""
Return
; ------------------------------------------------------------------------------
Check_CCAD:
; ------------------------------------------------------------------------------
; Contact Center Agent Desktop
; Height 147 ???
; Always on Top of Screen ???
; ahk_class WindowsForms10.Window.8.app8d
; If it isn't running, it will be started
If (CCAD_App <> "") {
   Process, Exist, %CCAD_App%
   If (Errorlevel = 0) {
      Run, "%CCAD_Path%%CCAD_App%", , UseErrorlevel
      If (Errorlevel = "ERROR") {
         MsgBox, Couldn't start %CCAD_App%
         Return
      }
   }
   Process, Wait, %CCAD_App%
}
CCAD_ID := WinExist("ahk_class WindowsForms10.Window.8.app8d")
If (CCAD_ID <> 0) {
;  WinGetPos, , , , CCAD_H, ahk_ID %CCAD_ID%
   IfWinExist, CustomerHistoryListForm
   {
      CCAD_H := 147
   } Else {
      CCAD_H := 49
   }
}
Return
; ------------------------------------------------------------------------------
Set_Working_Area:
; ------------------------------------------------------------------------------
; Sets/Restores working area dimensions
If (WA_Mode = "Set") {
   ; Set new dimensions
   _L := WA_Left
   _T := WA_Top
   _R := WA_Right
   _B := WA_Bottom
} Else If (WA_Mode = "Res") {
   ; Restore previous dimensions
   _L := MW_Left
   _T := MW_Top
   _R := MW_Right
   _B := MW_Bottom
} Else {
   Return
}
_Set_Work_Area(_L, _T, _R, _B)
; Check windows for resizing/restoring
WinGet, _ID, List, , , Program Manager
_I := _ID
Loop, %_ID%
{
   If ((_ID%_I% = Tray_ID) Or (_ID%_I% = Gui95_ID) Or (_ID%_I% = CCAD_ID)) {
      _I--
      Continue
   }
   If (WA_Mode = "Set") {
      _Check_Resize(_ID%_I%)
   } Else {
      _Check_Restore(_ID%_I%)
   }
   _I--
}
Return
; ------------------------------------------------------------------------------
Exit_App:
; ------------------------------------------------------------------------------
; Restores main Monitors working Area and exits
WA_Mode := "Res"
Gosub, Set_Working_Area
ExitApp
; ##############################################################################
; Functions
; ##############################################################################
; ------------------------------------------------------------------------------
; Set the current Work Area of the main Monitor
; Existing windows are resized!
; ------------------------------------------------------------------------------
_Set_Work_Area(Left, Top, Right, Bottom)
{
   SPI_SETWORKAREA := 0x2F
   VarSetCapacity(Area, 16)
   DllCall("ntoskrnl.exe\RtlFillMemoryUlong"
          , UInt, &Area + 0
          , UInt, 4
          , UInt, Left)
   DllCall("ntoskrnl.exe\RtlFillMemoryUlong"
          , UInt, &Area + 4
          , UInt, 4
          , UInt, Top)
   DllCall("ntoskrnl.exe\RtlFillMemoryUlong"
          , UInt, &Area + 8
          , UInt, 4
          , UInt, Right)
   DllCall("ntoskrnl.exe\RtlFillMemoryUlong"
          , UInt, &Area + 12
          , UInt, 4
          , UInt, Bottom)
   DllCall("SystemParametersInfo"
          , UInt, SPI_SETWORKAREA
          , UInt, 0
          , UInt, &Area
          , UInt,0)
   Sleep, 500
}
; ------------------------------------------------------------------------------
; Check Windows for Rezising
; ------------------------------------------------------------------------------
_Check_Resize(ID)
{
   Global
   Local X1, X2, Y1, Y2, W1, W2, H1, H2, MV
   MV := False
   WinGetPos, X1, Y1, W1, H1, ahk_id %ID%
   ; Save old Dimensions
   X2 := X1
   Y2 := Y1
   W2 := W1
   H2 := H1
   ; Check for Resizing
   If ((X2 < _L) And ((X2 + W2) > _L)) {
      X2 := _L
      MV := True
   }
   If ((Y2 < _T) And ((Y2 + H2) > _T)) {
      Y2 := _T
      MV := True
   }
   If (((Y2 + H2) > _B) And (Y2 < _B)) {
      H2 := _B - Y2
      MV := True
   }
   If (((X2 + W2) > _R) And (X2 < _R)) {
      W2 := _R - X2
      MV := True
   }
   If (MV) {
      ; Store old Values
      _ID%ID% := ID
      _X%ID% := X1
      _Y%ID% := Y1
      _W%ID% := W1
      _H%ID% := H1
      ; Resize to new values
      WinMove, ahk_id %ID%, , X2, Y2, W2, H2
   }
}
; ------------------------------------------------------------------------------
; Check Windows for Restoring previous Dimensions
; ------------------------------------------------------------------------------
_Check_Restore(ID)
{
   Global
   Local X, Y, W, H
   ; If _ID%_ID% is not empty
   If (_ID%ID%) {
      X := _X%ID%
      Y := _Y%ID%
      W := _W%ID%
      H := _H%ID%
      WinMove, ahk_id %ID%, , X, Y, W, H
   }
}